/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = rtsp_req.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/14 by songbb                               */
/*******************************************************************/

#include "conntrack.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "rtsp_core.h"
#include "rtsp_comm.h"
#include "rtsp_req.h"

/*******************************************************************************
*  FUNC     :  解析RTSP请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (RTSP私有的session)
*           :  *p_st_rtsp_packet                         (RTSP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __rtsp_unpack_req(Conntrack *p_st_conn
                                , L7session_rtsp *p_st_sess
                                , L7_rtsp_packet *p_st_rtsp_packet
                                , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_rtsp_private *p_st_session_private = (L7session_rtsp_private *) frct_get_session_private(p_st_session);
    L7_rtsp_stmt *p_st_rtsp_stmt = p_st_session_private->p_st_rtsp_stmt;
    int i_pos_eoh = 0;
    int i_pos_uri = 0;
    int i_pos_uri_len = 0;
    char *p_uri = NULL;
    int i_pos_header_fields = 0;
    int i_pos_colon = 0;
    char *p_field_name = NULL;
    char *p_field_value = NULL;
    char *p_field_value2 = NULL;
    char *p_field_value_whole = NULL;
    int i_pos_line_end = 0;
    uint8_t tmp;
    int i_append_first_value;
    Frstr *p_frstr = NULL;
    Frreport_body_data *p_st_body = NULL;
    char *p_report_key = NULL;
    int i_report_key_len = 0;

    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto error;

    // 查找CRLFCRLF
    if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, 0, bytebuff_length(p_st_rtsp_packet->p_st_packet), APM_RTSP_EOH, strlen(APM_RTSP_EOH), &i_pos_eoh) != FR_SUCC)
        goto error;

    // 查找first line的uri起始位置
    if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_SP, strlen(APM_RTSP_SP), &i_pos_uri) != FR_SUCC)
        goto error;
    i_pos_uri += strlen(APM_RTSP_SP);

    // 查找first line的uri结束位置
    if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, i_pos_uri, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_SP, strlen(APM_RTSP_SP), &i_pos_uri_len) != FR_SUCC)
        goto error;
    i_pos_uri_len -= i_pos_uri;

    if ((p_uri = (char *) frmalloc(sizeof(char) * (i_pos_uri_len + 1))) == NULL)
    {
        RTSP_MALLOCK_ERR;
        goto error;
    }
    if (bytebuff_get_bytes_at(p_st_rtsp_packet->p_st_packet, i_pos_uri, (unsigned int) (i_pos_uri_len), p_uri) != FR_SUCC)
        goto error;
    p_uri[i_pos_uri_len] = '\0';
    RTSP_PRINT_WARN("p_uri:[%s]\n", p_uri);

    // 确定header fields的起始行位置
    if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, 0, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_EOL, strlen(APM_RTSP_EOL), &i_pos_header_fields) != FR_SUCC)
        goto error;
    i_pos_header_fields += strlen(APM_RTSP_EOL);

    while (i_pos_header_fields < i_pos_eoh)
    {
        // 查找头域分隔符:的位置
        if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_COLON, strlen(APM_RTSP_COLON), &i_pos_colon) != FR_SUCC)
            goto error;
        i_pos_colon -= i_pos_header_fields;
        if (i_pos_colon == 0)
            goto error;
        i_pos_colon += i_pos_header_fields;
        // 取field name值
        if ((p_field_name = (char *) frmalloc(sizeof(char) * (i_pos_colon - i_pos_header_fields + 1))) == NULL)
        {
            RTSP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_colon - i_pos_header_fields), p_field_name) != FR_SUCC)
            goto error;
        p_field_name[i_pos_colon - i_pos_header_fields] = '\0';
        frtrim(p_field_name);
//        RTSP_PRINT_WARN("p_field_name:[%s]\n", p_field_name);
        i_append_first_value = FR_NO;

        // 查找当前行的结束位置
        if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, i_pos_colon, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_EOL, strlen(APM_RTSP_EOL), &i_pos_line_end) != FR_SUCC)
            goto error;
        i_pos_line_end -= i_pos_colon;
        if (i_pos_line_end == 0)
            goto error;
        i_pos_line_end += i_pos_colon;

        // 取field value值
        if ((p_field_value = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_colon - 1 + 1))) == NULL)
        {
            RTSP_MALLOCK_ERR;
            goto error;
        }
        if (bytebuff_get_bytes_at(p_st_rtsp_packet->p_st_packet, i_pos_colon + 1, (unsigned int) (i_pos_line_end - i_pos_colon - 1), p_field_value) != FR_SUCC)
            goto error;
        p_field_value[i_pos_line_end - i_pos_colon - 1] = '\0';
        frtrim(p_field_value);

        i_pos_header_fields = i_pos_line_end + strlen(APM_RTSP_EOL);

        if (i_pos_header_fields < i_pos_eoh)
        {
            if (bytebuffer_get_at(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                goto error;
            while (tmp == ' ' || tmp == '\t') // 多行field value
            {
                // 查找当前行的结束位置
                if (bytebuff_memstr(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, i_pos_eoh + (int) strlen(APM_RTSP_EOH), APM_RTSP_EOL, strlen(APM_RTSP_EOL), &i_pos_line_end) != FR_SUCC)
                    goto error;
                i_pos_line_end -= i_pos_header_fields;
                if (i_pos_line_end == 0)
                    goto error;
                i_pos_line_end += i_pos_header_fields;

                // 先插入第一个value
                if (i_append_first_value == FR_NO)
                {
                    if ((p_frstr = frstr_new(64)) == NULL)
                        goto error;
                    if (frstr_append(p_frstr, p_field_value, strlen(p_field_value)) != FR_SUCC)
                        goto error;
                    rtsp_free((void **) &p_field_value);
                    i_append_first_value = FR_YES;
                }

                // 取field value值
                if ((p_field_value2 = (char *) frmalloc(sizeof(char) * (i_pos_line_end - i_pos_header_fields + 1))) == NULL)
                {
                    RTSP_MALLOCK_ERR;
                    goto error;
                }
                if (bytebuff_get_bytes_at(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, (unsigned int) (i_pos_line_end - i_pos_header_fields), p_field_value2) != FR_SUCC)
                    goto error;
                p_field_value2[i_pos_line_end - i_pos_header_fields] = '\0';
                frtrim(p_field_value2);
                if (frstr_append(p_frstr, " ,", 2) != FR_SUCC)
                    goto error;
                if (frstr_append(p_frstr, p_field_value2, strlen(p_field_value2)) != FR_SUCC)
                    goto error;
                rtsp_free((void **) &p_field_value2);

                i_pos_header_fields = i_pos_line_end + strlen(APM_RTSP_EOL);

                if (i_pos_header_fields >= i_pos_eoh)
                    break;
                if (bytebuffer_get_at(p_st_rtsp_packet->p_st_packet, i_pos_header_fields, &tmp) != FR_SUCC)
                    goto error;
            }
        }

        if (i_append_first_value == FR_YES)
            p_field_value_whole = frstr_free2(&p_frstr);
        else
            p_field_value_whole = p_field_value;
//        RTSP_PRINT_WARN("p_field_value_whole:[%s]\n", p_field_value_whole);

        if (strcasecmp(p_field_name, "Authorization") == 0)
        {
            // TODO: 取username
        }

        // 过滤敏感字段
        if (strcasecmp(p_field_name, "Authorization") == 0 ||
            strcasecmp(p_field_name, "Proxy-Authorization") == 0 ||
            strcasecmp(p_field_name, "Proxy-Authenticate") == 0 ||
            strcasecmp(p_field_name, "WWW-Authenticate") == 0)
        {
            rtsp_free((void **) &p_field_name);
            rtsp_free((void **) &p_field_value_whole);
            continue;
        }

        if (frstrlower(p_field_name, strlen(p_field_name)) != FR_SUCC)
            goto error;
        i_report_key_len = strlen(APM_RTSP_REPORT_REQ_HDR_PREFIX) + strlen(p_field_name) + 1;
        if ((p_report_key = (char *) frmalloc(sizeof(char) * i_report_key_len)) == NULL)
        {
            RTSP_MALLOCK_ERR;
            goto error;
        }
        snprintf(p_report_key, (size_t) i_report_key_len, APM_RTSP_REPORT_REQ_HDR_PREFIX"%s", p_field_name);
        if (frreport_body_l7_add_str(p_st_body, p_report_key, p_field_value_whole) != FR_SUCC)
            goto error;

        rtsp_free((void **) &p_field_name);
        rtsp_free((void **) &p_field_value_whole);
        rtsp_free((void **) &p_report_key);
    }

    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto error;
    if (p_st_sess->p_username != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_USERNAME, p_st_sess->p_username) != FR_SUCC)
            goto error;
    }
    if (p_st_sess->p_server != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_SERVER, p_st_sess->p_server) != FR_SUCC)
            goto error;
    }
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, p_uri) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, FR_YES) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, &(p_st_rtsp_packet->st_timestamp_first)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, &(p_st_rtsp_packet->st_timestamp_last)) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_long(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, frtime_diff(&(p_st_rtsp_packet->st_timestamp_first), &(p_st_rtsp_packet->st_timestamp_last))) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_rtsp_packet->ui_length) != FR_SUCC)
        goto error;

    frreport_body_l7list_free(&(p_st_session_private->p_report_comm));
    p_st_session_private->p_report_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_body);

    if (frreport_body_l7_add_str(p_st_body, APM_RTSP_REPORT_REQ_URI, p_uri) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_str(p_st_body, APM_RTSP_REPORT_REQ_METHOD, p_st_rtsp_packet->p_req_method) != FR_SUCC)
        goto error;

    frreport_body_l7list_free(&(p_st_session_private->p_report_req));
    p_st_session_private->p_report_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_body);

    if (rtsp_report_data(p_st_conn, FR_YES, p_st_body, p_st_hash_report) != FR_SUCC)
        goto error;

    p_st_rtsp_stmt->st_req_end_timestamp.tv_sec = p_st_rtsp_packet->st_timestamp_last.tv_sec;
    p_st_rtsp_stmt->st_req_end_timestamp.tv_usec = p_st_rtsp_packet->st_timestamp_last.tv_usec;

    p_st_rtsp_stmt->em_req_method = p_st_rtsp_packet->em_req_method;

    rtsp_free((void **) &p_uri);

    return FR_SUCC;
error:
    rtsp_free((void **) &p_uri);
    rtsp_free((void **) &p_field_name);
    rtsp_free((void **) &p_field_value_whole);
    rtsp_free((void **) &p_field_value2);
    frstr_free(&p_frstr);
    frreport_body_free(&p_st_body);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  解析RTSP请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (RTSP私有的session)
*           :  *p_st_rtsp_packet                        (RTSP数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int rtsp_analyze_req(Conntrack *p_st_conn
                    , L7session_rtsp *p_st_sess
                    , L7_rtsp_packet *p_st_rtsp_packet
                    , Frhash_header *p_st_hash_report)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_rtsp_private *p_st_session_private = (L7session_rtsp_private *) frct_get_session_private(p_st_session);

    RTSP_PRINT_FATAL("method:[%s]\n", p_st_rtsp_packet->p_req_method);
    
    rtsp_init_stmt(p_st_session_private->p_st_rtsp_stmt);
    
    switch (p_st_rtsp_packet->em_req_method)
    {
        case RTSP_METHOD_TYPE_OPTIONS:
        case RTSP_METHOD_TYPE_DESCRIBE:
        case RTSP_METHOD_TYPE_SETUP:
        case RTSP_METHOD_TYPE_PLAY:
        case RTSP_METHOD_TYPE_PAUSE:
        case RTSP_METHOD_TYPE_GET_PARAMETER:
        case RTSP_METHOD_TYPE_SET_PARAMETER:
        case RTSP_METHOD_TYPE_ANNOUNCE:
        case RTSP_METHOD_TYPE_REDIRECT:
        case RTSP_METHOD_TYPE_RECORD:
        case RTSP_METHOD_TYPE_TEARDOWN:
            if (__rtsp_unpack_req(p_st_conn, p_st_sess, p_st_rtsp_packet, p_st_hash_report) != FR_SUCC)
                goto error;
            break;
        default:
            ;
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}
